home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / fontutil.6 / fontutil / fontutils-0.6 / limn / pxl-outline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-11  |  6.4 KB  |  224 lines

  1. /* pxl-outline.c: find the edges of the bitmap image; we call each such
  2.    edge an ``outline''; each outline is made up of one or more pixels;
  3.    and each pixel participates via one or more edges.
  4.  
  5. Copyright (C) 1992 Free Software Foundation, Inc.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #include "config.h"
  22.  
  23. #include "bitmap.h"
  24. #include "edge.h"
  25. #include "font.h"
  26. #include "logreport.h"
  27.  
  28. #include "pxl-outline.h"
  29.  
  30.  
  31. static pixel_outline_type find_one_outline (char_info_type, edge_type,
  32.                           unsigned, unsigned, bitmap_type *);
  33. static void append_pixel_outline (pixel_outline_list_type *, 
  34.                                   pixel_outline_type);
  35. static pixel_outline_type new_pixel_outline (void);
  36. static void append_outline_pixel (pixel_outline_type *, coordinate_type);
  37. static void append_coordinate (pixel_outline_type *, int, int, edge_type);
  38.  
  39.  
  40.  
  41. /* A character is made up of a list of one or more outlines.  Here, we
  42.    go through a character's bitmap top to bottom, left to right, looking
  43.    for the next pixel with an unmarked edge also on the character's outline.
  44.    Each one of these we find is the starting place for one outline.  We
  45.    find these outlines and put them in a list to return.  */
  46.  
  47. pixel_outline_list_type
  48. find_outline_pixels (char_info_type c)
  49. {
  50.   pixel_outline_list_type outline_list;
  51.   unsigned row, col;
  52.   bitmap_type bitmap = CHAR_BITMAP (c);
  53.   bitmap_type marked = new_bitmap (BITMAP_DIMENSIONS (bitmap));
  54.  
  55.   O_LIST_LENGTH (outline_list) = 0;
  56.   outline_list.data = NULL;
  57.  
  58.   for (row = 0; row < BITMAP_HEIGHT (bitmap); row++)
  59.     for (col = 0; col < BITMAP_WIDTH (bitmap); col++)
  60.       {
  61.     edge_type edge;
  62.         
  63.         if (BITMAP_PIXEL (bitmap, row, col) == WHITE)
  64.           continue;
  65.         
  66.         edge = next_unmarked_outline_edge (row, col, START_EDGE, bitmap,
  67.                                            marked);
  68.  
  69.     if (edge != no_edge)
  70.       {
  71.             pixel_outline_type outline;
  72.             boolean clockwise = edge == bottom;
  73.             
  74.             LOG2 ("#%u: (%sclockwise)", O_LIST_LENGTH (outline_list),
  75.                                         clockwise ? "" : "counter"); 
  76.  
  77.             outline = find_one_outline (c, edge, row, col, &marked);
  78.             
  79.             /* Outside outlines will start at a top edge, and move
  80.                counterclockwise, and inside outlines will start at a
  81.                bottom edge, and move clockwise.  This happens because of
  82.                the order in which we look at the edges.  */
  83.             O_CLOCKWISE (outline) = clockwise;
  84.         append_pixel_outline (&outline_list, outline);
  85.  
  86.             REPORT (".");
  87.             LOG1 (" [%u].\n", O_LENGTH (outline));
  88.       }
  89.       }
  90.  
  91.   free_bitmap (&marked);
  92.   
  93.   return outline_list;
  94. }
  95.  
  96.  
  97. /* Here we find one of a character C's outlines.  We're passed the
  98.    position (ORIGINAL_ROW and ORIGINAL_COL) of a starting pixel and one
  99.    of its unmarked edges, ORIGINAL_EDGE.  We traverse the adjacent edges
  100.    of the outline pixels, appending to the coordinate list.  We keep
  101.    track of the marked edges in MARKED, so it should be initialized to
  102.    zeros when we first get it.  */
  103.  
  104. static pixel_outline_type
  105. find_one_outline (char_info_type c, edge_type original_edge,
  106.           unsigned original_row, unsigned original_col,
  107.           bitmap_type *marked)
  108. {
  109.   pixel_outline_type outline = new_pixel_outline ();
  110.   bitmap_type bitmap = CHAR_BITMAP (c);
  111.   unsigned row = original_row, col = original_col;
  112.   edge_type edge = original_edge;
  113.  
  114.   do
  115.     {
  116.       /* Put this edge on to the output list, changing to Cartesian, and
  117.          taking account of the side bearings.  */
  118.       append_coordinate (&outline, col + CHAR_MIN_COL (c), 
  119.                          CHAR_MAX_ROW (c) - row, edge);
  120.  
  121.       mark_edge (edge, row, col, marked);
  122.       next_outline_edge (bitmap, &edge, &row, &col);
  123.     }
  124.   while (row != original_row || col != original_col || edge != original_edge);
  125.  
  126.   return outline;
  127. }
  128.  
  129.  
  130.  
  131. /* Append an outline to an outline list.  This is called when we have
  132.    completed an entire pixel outline.  */
  133.  
  134. static void
  135. append_pixel_outline (pixel_outline_list_type *outline_list,
  136.               pixel_outline_type outline)
  137. {
  138.   O_LIST_LENGTH (*outline_list)++;
  139.   XRETALLOC (outline_list->data, outline_list->length, pixel_outline_type);
  140.   O_LIST_OUTLINE (*outline_list, O_LIST_LENGTH (*outline_list) - 1) = outline;
  141. }
  142.  
  143.  
  144. /* Here is a routine that frees a list of such lists.  */
  145.  
  146. void
  147. free_pixel_outline_list (pixel_outline_list_type *outline_list)
  148. {
  149.   unsigned this_outline;
  150.  
  151.   for (this_outline = 0; this_outline < outline_list->length; this_outline++)
  152.     {
  153.       pixel_outline_type o = outline_list->data[this_outline];
  154.       safe_free ((address *) &(o.data));
  155.     }
  156.  
  157.   if (outline_list->data != NULL)
  158.     safe_free ((address *) &(outline_list->data));
  159. }
  160.  
  161.  
  162.  
  163. /* Return an empty list of pixels.  */
  164.    
  165.  
  166. pixel_outline_type
  167. new_pixel_outline ()
  168. {
  169.   pixel_outline_type pixel_outline;
  170.  
  171.   O_LENGTH (pixel_outline) = 0;
  172.   pixel_outline.data = NULL;
  173.  
  174.   return pixel_outline;
  175. }
  176.  
  177.  
  178. /* Add the coordinate C to the pixel list O.  */
  179.  
  180. static void
  181. append_outline_pixel (pixel_outline_type *o, coordinate_type c)
  182. {
  183.   O_LENGTH (*o)++;
  184.   XRETALLOC (o->data, O_LENGTH (*o), coordinate_type);
  185.   O_COORDINATE (*o, O_LENGTH (*o) - 1) = c;
  186. }
  187.  
  188.  
  189. /* We are given an (X,Y) in Cartesian coordinates, and the edge of the pixel
  190.    we're on.  We append a corner of that pixel as our coordinate.
  191.    If we're on a top edge, we use the upper-left hand corner; right edge
  192.    => upper right; bottom edge => lower right; left edge => lower left.  */
  193.  
  194. void
  195. append_coordinate (pixel_outline_type *o, int x, int y, edge_type edge)
  196. {
  197.   coordinate_type c = { x, y};
  198.  
  199.   switch (edge)
  200.     {
  201.     case top:
  202.       c.y++;
  203.       break;
  204.     
  205.     case right:
  206.       c.x++;
  207.       c.y++;
  208.       break;
  209.     
  210.     case bottom:
  211.       c.x++;
  212.       break;
  213.     
  214.     case left:
  215.       break;
  216.     
  217.     default:
  218.       FATAL1 ("append_coordinate: Bad edge (%d)", edge);
  219.     }
  220.  
  221.   LOG2 (" (%d,%d)", c.x, c.y);
  222.   append_outline_pixel (o, c);
  223. }
  224.